package com.night.icm.service.business.service;

import com.github.wenhao.jpa.Specifications;
import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.model.business.SystemFileDTO;
import com.night.icm.persistence.business.entity.SystemFile;
import com.night.icm.persistence.business.reporsitory.SystemFileRepository;
import com.night.icm.service.business.mapper.SystemFileMapper;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Optional;

/**
 * SystemFileServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2020/3/8
 */
@Slf4j
@Service()
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class SystemFileServiceImpl implements SystemFileService {

    private final SystemFileRepository systemFileRepository;
    private final FileStorageService fileStorageService;
    private final SystemFileMapper systemFileMapper;

    @Autowired
    public SystemFileServiceImpl(SystemFileRepository systemFileRepository,
                                 FileStorageService fileStorageService,
                                 SystemFileMapper systemFileMapper) {
        this.fileStorageService = fileStorageService;
        this.systemFileMapper = systemFileMapper;
        this.systemFileRepository = systemFileRepository;
    }

    /**
     * 保存文件
     *
     * @param type  类型，用于标识文件属于某一业务种类，并非文件的格式
     * @param files 要保存的文件
     * @param types
     * @return 已保存的文件信息
     * @throws IOException 找不到ID对应的文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SystemFileDTO[] persist(String type, File[] files, List<String> types) throws IOException {
        SystemFile systemFile;
        SystemFile[] systemFiles = new SystemFile[files.length];
        int i = 0;
        int t = 0;
        for (File f : files) {
            systemFile = createSystemFile(types == null ? type : types.get(t++), f);
            systemFile.setName(fileStorageService.save(f));
            systemFileRepository.saveAndFlush(systemFile);
            systemFiles[i++] = systemFile;
        }
        return systemFileMapper.toArraySysFileDTO(systemFiles);
    }

    /**
     * 新建SystemFile对象，并将File信息传入新建SystemFile对象对象
     *
     * @param type 文件类型
     * @param file 文件对象
     * @return SystemFile
     */
    private SystemFile createSystemFile(String type, File file) {
        SystemFile systemFile = new SystemFile();

        // 去除加上的时间戳，取得原文件名
        systemFile.setOriginalName(FilenameUtils.getName(file.getName()));
        systemFile.setSize(file.length());
        systemFile.setType(type);
        return systemFile;
    }

    /**
     * 删除文件
     *
     * @param fileId 文件id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFile(String fileId) {
        Optional<SystemFile> systemFileOptional = systemFileRepository.findById(Long.valueOf(fileId));
        if (!systemFileOptional.isPresent()) {
            throw new NoSuchDataException(fileId);
        }
        SystemFile systemFile = systemFileOptional.get();
        systemFileRepository.delete(systemFile);
        fileStorageService.delete(systemFile.getName());
    }

    /**
     * 根据文件ID查询文件
     *
     * @param fileId 文件ID
     * @return SystemFileDTO
     */
    @Override
    public SystemFileDTO findById(String fileId) {
        Optional<SystemFile> systemFileOptional = systemFileRepository.findById(Long.valueOf(fileId));
        if (!systemFileOptional.isPresent()) {
            throw new NoSuchDataException(fileId);
        }
        return systemFileMapper.toSystemFileDTO(systemFileOptional.get());
    }

    /**
     * 复制文件
     *
     * @param type 文件的类型
     * @param id   文件的ID
     * @return 文件对象
     * @throws IOException 文件流异常
     */
    @Override
    public SystemFileDTO copy(String type, String id) throws IOException {
        Optional<SystemFile> systemFileOptional = systemFileRepository.findById(Long.valueOf(id));
        if (!systemFileOptional.isPresent()) {
            throw new NoSuchDataException(id);
        }
        SystemFile systemFile = systemFileOptional.get();
        File[] systemFiles = {getFile(systemFile.getName())};
        return persist(type, systemFiles, null)[0];
    }

    /**
     * 通过保存的文件名来取文件
     *
     * @param name 文件名或key
     * @return 保存的文件
     * @throws IOException 找不到ID对应的文件
     */
    @Override
    public File getFile(String name) throws IOException {
        return fileStorageService.get(name);
    }

    /**
     * 识别图片或pdf文件转成txt文件
     *
     * @param resourceFile 图片或pdf文件
     * @return SystemFileDTO
     * @throws IOException        无法找到文件或失败则抛出异常
     * @throws TesseractException 图片识别错误抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SystemFileDTO getTxtFile(File resourceFile) throws IOException, TesseractException {
        File txtFile = fileStorageService.getTxtFile(resourceFile);
        File[] files = new File[]{txtFile};
        SystemFileDTO[] systemFileDTOS = this.persist("全文检索引用的txt文件", files, null);
        return systemFileDTOS[0];
    }

    /**
     * @param page         页号
     * @param size         每页纪录条数
     * @param sort         排序字段, 例如：字段1,asc,字段2,desc
     * @param originalName 文件原始名称
     * @param type         文件类型
     * @return 全局参数配置dto信息集合
     */
    @Override
    public PageDataDTO<SystemFileDTO> findOnePage(int page, int size, String sort, String originalName, String type) {
        Page<SystemFile> systemFilePage = systemFileRepository.findAll(
                Specifications.<SystemFile>and()
                        .like(StringUtils.isNotBlank(originalName), "originalName", "%" + originalName + "%")
                        .like(StringUtils.isNotBlank(type), "type", "%" + type + "%")
                        .build(), PageHelper.generatePageRequest(page, size, sort));
        List<SystemFileDTO> list = systemFileMapper.toListSystemFileDTO(systemFilePage.getContent());
        return PageDataUtil.toPageData(systemFilePage, list);
    }
}